package com.czh.auth.domain.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.czh.auth.common.constants.RedisKeyConstant;
import com.czh.auth.common.enums.AuthStatusEnums;
import com.czh.auth.common.enums.IsDeletedEnums;
import com.czh.auth.common.constants.AuthConstant;
import com.czh.auth.domain.convert.AuthUserDomainConverter;
import com.czh.auth.domain.entity.AuthUserBO;
import com.czh.auth.domain.redis.RedisUtil;
import com.czh.auth.domain.service.AuthUserDomainService;
import com.czh.auth.infra.basic.entity.*;
import com.czh.auth.infra.basic.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @author caozaihui
 * @version 1.0
 * @since 2024/8/28 上午 11:09
 */
@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    private final AuthUserService authUserService;

    private final AuthUserRoleService authUserRoleService;

    private final AuthRoleService authRoleService;

    private final AuthRolePermissionService authRolePermissionService;

    private final AuthPermissionService authPermissionService;

    private final RedisUtil redisUtil;

    AuthUserDomainServiceImpl(AuthUserService authUserService, AuthUserRoleService authUserRoleService,
                              AuthRoleService authRoleService, AuthRolePermissionService authRolePermissionService,
                              AuthPermissionService authPermissionService, RedisUtil redisUtil) {
        this.authUserService = authUserService;
        this.authUserRoleService = authUserRoleService;
        this.authRoleService = authRoleService;
        this.authRolePermissionService = authRolePermissionService;
        this.authPermissionService = authPermissionService;
        this.redisUtil = redisUtil;
    }
    /**
     * 将权限和角色写入缓存
     * @param authUser
     * @return
     */
    private Boolean setRedisCache(AuthUser authUser) {
        //将角色写入缓存

        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(authUser.getId());
        List<AuthUserRole> userRoleList = authUserRoleService.queryAuthUserRoleList(authUserRole);
        if (CollectionUtils.isEmpty(userRoleList)){
            return false;
        }
        AuthRole authRole = new AuthRole();
        authRole.setId(userRoleList.get(0).getRoleId());
        AuthRole redisAuthRole = authRoleService.queryAuthRole(authRole);
        List<AuthRole> authUserList = new LinkedList<>();
        authUserList.add(redisAuthRole);
        long userRole = redisUtil.setCacheList(RedisUtil.buildKey(RedisKeyConstant.authRolePrefix, String.valueOf(authUser.getUserName())), authUserList);

        //将权限写入缓存
        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(redisAuthRole.getId());
        List<Long> authRolePermissionIds = authRolePermissionService.queryAuthRolePermissionList(authRolePermission).
                stream().map(AuthRolePermission::getPermissionId).toList();
        List<AuthPermission> authPermissionList = authPermissionService.queryAuthPermissionListByIds(authRolePermissionIds);
        if (CollectionUtils.isEmpty(authPermissionList)){
            return false;
        }
        return redisUtil.setCacheList(RedisUtil.buildKey(RedisKeyConstant.authPermissionPrefix, authUser.getUserName()), authPermissionList) > 0;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        AuthUser exitUser = new AuthUser();
        exitUser.setUserName(authUserBO.getUserName());
        exitUser.setIsDeleted(IsDeletedEnums.NO_DELETED.getCode());

        AuthUser authUser = AuthUserDomainConverter.INSTANCE.convert(authUserBO);
        // 扫码登录时没有密码
        if (Objects.nonNull(authUserBO.getPassword()) && !authUserBO.getPassword().isEmpty()) {
            try {
                authUser.setPassword(BCrypt.hashpw(authUserBO.getPassword(), BCrypt.gensalt(12)));
            } catch (Exception e) {
                throw new RuntimeException("密码哈希失败", e);
            }
        }
        /*往下正常注册流程*/
        authUser.setStatus(AuthStatusEnums.NORMAL.getCode());
        authUserService.insert(authUser);

        //关联角色,虽然劳资知道是普通角色,但是为了健壮性还是查一下
        AuthRole norMalUserRole = new AuthRole();
        norMalUserRole.setRoleKey(AuthConstant.NORMAL);
        AuthRole redisAuthRole = authRoleService.queryAuthRole(norMalUserRole);
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(authUser.getId());
        authUserRole.setRoleId(redisAuthRole.getId());
        authUserRoleService.insert(authUserRole);

        return setRedisCache(authUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SaTokenInfo doLogin(String captcha) {
        String buildKey = RedisUtil.buildKey(RedisKeyConstant.authCodePrefix, captcha);
        String userOpenId = (String) redisUtil.getCacheObject(buildKey);
        if (Objects.isNull(userOpenId)) {
            return null;
        }
        AuthUser authUser = new AuthUser();
        authUser.setUserName(userOpenId);
        List<AuthUser> authUserList = authUserService.queryAuthUserList(authUser);
        setRedisCache(authUserList.get(0));
        StpUtil.login(userOpenId);
        return StpUtil.getTokenInfo();
    }

    @Override
    public Boolean logout(String userName) {
        StpUtil.logout(userName);
        boolean permission = redisUtil.deleteObject(RedisUtil.buildKey(RedisKeyConstant.authPermissionPrefix, userName));
        boolean role = redisUtil.deleteObject(RedisUtil.buildKey(RedisKeyConstant.authRolePrefix, userName));
        return permission || role;
    }
    @Override
    public Boolean updateUserInfo(AuthUserBO authUserBO) {
        return authUserService.update(AuthUserDomainConverter.INSTANCE.convert(authUserBO)) > 0;
    }

    @Override
    public Boolean deleteUser(Long id) {
        return authUserService.removeById(id);
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setIsDeleted(IsDeletedEnums.NO_DELETED.getCode());
        authUser.setUserName(authUserBO.getUserName());

        try {
            List<AuthUser> authUserList = authUserService.queryAuthUserList(authUser);
            if (authUserList.isEmpty()) {
                log.warn("No user found for username: {}", authUserBO.getUserName());
                return null;
            }
            if (authUserList.size() > 1) {
                log.warn("重复用户: {}..", authUserBO.getUserName());
            }
            return AuthUserDomainConverter.INSTANCE.convert(authUserList.get(0));
        } catch (Exception e) {
            log.error("Error querying user list", e);
            return null;
        }
    }

    @Override
    public List<AuthUserBO> getUserInfoList(List<String> userNameList) {
        List<AuthUser> userInfoList = authUserService.getUserInfoList(userNameList);
        if (userInfoList.isEmpty()) {
            return Collections.emptyList();
        }
        return AuthUserDomainConverter.INSTANCE.convert(userInfoList);
    }
}
